/*
 * MIT License
 *
 * Copyright (c) 2023 北京凯特伟业科技有限公司
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package com.je.bpm.api.runtime.task.conf;

import com.je.bpm.api.runtime.shared.conf.CommonRuntimeAutoConfiguration;
import com.je.bpm.api.runtime.task.TaskOperatorServiceImpl;
import com.je.bpm.api.runtime.task.conf.impl.TaskRuntimeConfigurationImpl;
import com.je.bpm.api.runtime.task.event.impl.*;
import com.je.bpm.api.runtime.task.event.internal.*;
import com.je.bpm.api.runtime.task.impl.APITaskCandidateGroupConverter;
import com.je.bpm.api.runtime.task.impl.APITaskCandidateUserConverter;
import com.je.bpm.api.runtime.task.impl.APITaskConverter;
import com.je.bpm.api.runtime.task.operator.*;
import com.je.bpm.engine.RepositoryService;
import com.je.bpm.engine.RuntimeService;
import com.je.bpm.engine.TaskService;
import com.je.bpm.engine.delegate.DelegateExecution;
import com.je.bpm.engine.delegate.event.ActivitiEventType;
import com.je.bpm.engine.impl.cfg.ProcessEngineConfigurationImpl;
import com.je.bpm.engine.impl.persistence.entity.ExecutionEntity;
import com.je.bpm.engine.upcoming.ActivitiUpcomingRun;
import com.je.bpm.model.task.runtime.events.*;
import com.je.bpm.runtime.shared.event.listener.VariableEventListener;
import com.je.bpm.runtime.task.TaskOperatorService;
import com.je.bpm.runtime.task.conf.TaskRuntimeConfiguration;
import com.je.bpm.runtime.task.events.listener.TaskRuntimeEventListener;
import com.je.bpm.runtime.task.operator.*;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.List;

import static java.util.Collections.emptyList;

@Configuration
@AutoConfigureAfter(CommonRuntimeAutoConfiguration.class)
public class TaskRuntimeAutoConfiguration {

    @Bean
    public TaskOperatorService taskOperatorService(TaskCancelDelegateOperator taskCancelDelegateOperator, TaskChangeAssigneeOperator taskChangeAssigneeOperator,
                                                   TaskClaimOperator taskClaimOperator, TaskDelayOperator taskDelayOperator,
                                                   TaskDelegateOperator taskDelegateOperator, TaskDirectSendOperator taskDirectSendOperator,
                                                   TaskDismissOperator taskDismissOperator, TaskGobackOperator taskGobackOperator,
                                                   TaskPassRoundOperator taskPassRoundOperator, TaskPassRoundReadOperator taskPassRoundReadOperator,
                                                   TaskRetreiveOperator taskRetreiveOperator, TaskSubmitOperator taskSubmitOperator,
                                                   TaskTransferOperator taskTransferOperator, TaskUrgeOperator taskUrgeOperator, TaskPassOperator taskPassOperator,
                                                   TaskVetoOperator taskVetoOperator, TaskAbstainOperator taskAbstainOperator,
                                                   TaskRebookOperator taskRebookOperator, TaskCountersignReductionOperator taskCountersignReductionOperator,
                                                   TaskCountersignAddSignatureOperator taskCountersignAddSignatureOperator,
                                                   TaskPersonnelAdjustmentsOperator taskPersonnelAdjustmentsOperator) {
        return new TaskOperatorServiceImpl(taskCancelDelegateOperator, taskChangeAssigneeOperator, taskClaimOperator,
                taskDelayOperator, taskDelegateOperator, taskDirectSendOperator, taskDismissOperator,
                taskGobackOperator, taskPassRoundOperator, taskPassRoundReadOperator, taskRetreiveOperator,
                taskSubmitOperator, taskTransferOperator, taskUrgeOperator, taskPassOperator, taskVetoOperator, taskAbstainOperator,
                taskRebookOperator, taskCountersignReductionOperator, taskCountersignAddSignatureOperator, taskPersonnelAdjustmentsOperator);
    }

    @Bean
    public TaskDelayOperator taskDelayOperator(APITaskConverter apiTaskConverter, TaskService taskService) {
        return new TaskDelayOperatorImpl(apiTaskConverter, taskService);
    }

    @Bean
    public TaskClaimOperator taskClaimOperator(APITaskConverter apiTaskConverter, TaskService taskService, ActivitiUpcomingRun activitiUpcomingRun) {
        return new TaskClaimOperatorImpl(apiTaskConverter, taskService, activitiUpcomingRun);
    }

    @Bean
    public TaskPassOperator taskPassOperator(APITaskConverter apiTaskConverter, TaskService taskService, ActivitiUpcomingRun activitiUpcomingRun) {
        return new TaskPassOperatorImpl(apiTaskConverter, taskService, activitiUpcomingRun);
    }

    @Bean
    public TaskVetoOperator taskVetoOperator(APITaskConverter apiTaskConverter, TaskService taskService, ActivitiUpcomingRun activitiUpcomingRun) {
        return new TaskVetoOperatorImpl(apiTaskConverter, taskService, activitiUpcomingRun);
    }

    @Bean
    public TaskAbstainOperator taskAbstainOperator(APITaskConverter apiTaskConverter, TaskService taskService, ActivitiUpcomingRun activitiUpcomingRun) {
        return new TaskAbstainOperatorImpl(apiTaskConverter, taskService, activitiUpcomingRun);
    }

    @Bean
    public TaskCountersignAddSignatureOperator taskCountersignAddSignatureOperator(APITaskConverter apiTaskConverter, TaskService taskService) {
        return new TaskCountersignAddSignatureOperatorImpl(apiTaskConverter, taskService);
    }

    @Bean
    public TaskPersonnelAdjustmentsOperator taskPersonnelAdjustmentsOperator(APITaskConverter apiTaskConverter, TaskService taskService) {
        return new TaskPersonnelAdjustmentsOperatorImpl(apiTaskConverter, taskService);
    }

    @Bean
    public TaskCountersignReductionOperator taskCountersignReductionOperator(APITaskConverter apiTaskConverter, TaskService taskService) {
        return new TaskCountersignReductionOperatorImpl(apiTaskConverter, taskService);
    }

    @Bean
    public TaskRebookOperator taskRebookOperator(APITaskConverter apiTaskConverter, TaskService taskService) {
        return new TaskRebookOperatorImpl(apiTaskConverter, taskService);
    }

    @Bean
    public TaskChangeAssigneeOperator taskChangeAssigneeOperator(APITaskConverter apiTaskConverter, TaskService taskService,ActivitiUpcomingRun activitiUpcomingRun) {
        return new TaskChangeAssigneeOperatorImpl(apiTaskConverter, taskService,activitiUpcomingRun);
    }

    @Bean
    public TaskDelegateOperator taskDelegateOperator(APITaskConverter apiTaskConverter, TaskService taskService, ActivitiUpcomingRun activitiUpcomingRun, RepositoryService repositoryService, ProcessEngineConfigurationImpl processEngineConfiguration) {
        return new TaskDelegateOperatorImpl(apiTaskConverter, taskService, activitiUpcomingRun,repositoryService, processEngineConfiguration);
    }

    @Bean
    public TaskCancelDelegateOperator taskCancelDelegateOperator(APITaskConverter apiTaskConverter, TaskService taskService, ActivitiUpcomingRun activitiUpcomingRun) {
        return new TaskCancelDelegateOperatorImpl(apiTaskConverter, taskService, activitiUpcomingRun);
    }

    @Bean
    public TaskDirectSendOperator taskDirectSendOperator(APITaskConverter apiTaskConverter, TaskService taskService, ActivitiUpcomingRun activitiUpcomingRun) {
        return new TaskDirectSendOperatorImpl(apiTaskConverter, taskService, activitiUpcomingRun);
    }

    @Bean
    public TaskDismissOperator taskDismissOperator(APITaskConverter apiTaskConverter, TaskService taskService, ActivitiUpcomingRun activitiUpcomingRun) {
        return new TaskDismissOperatorImpl(apiTaskConverter, taskService, activitiUpcomingRun);
    }

    @Bean
    public TaskGobackOperator taskGobackOperator(APITaskConverter apiTaskConverter, TaskService taskService, ActivitiUpcomingRun activitiUpcomingRun) {
        return new TaskGobackOperatorImpl(apiTaskConverter, taskService, activitiUpcomingRun);
    }

    @Bean
    public TaskPassRoundOperator taskPassRoundOperator(APITaskConverter apiTaskConverter, TaskService taskService, ActivitiUpcomingRun activitiUpcomingRun) {
        return new TaskPassRoundOperatorImpl(apiTaskConverter, taskService, activitiUpcomingRun);
    }

    @Bean
    public TaskPassRoundReadOperator taskPassRoundReadOperator(APITaskConverter apiTaskConverter, TaskService taskService, ActivitiUpcomingRun activitiUpcomingRun) {
        return new TaskPassRoundReadOperatorImpl(apiTaskConverter, taskService, activitiUpcomingRun);
    }

    @Bean
    public TaskRetreiveOperator taskRetreiveOperator(APITaskConverter apiTaskConverter, TaskService taskService, ActivitiUpcomingRun activitiUpcomingRun) {
        return new TaskRetreiveOperatorImpl(apiTaskConverter, taskService, activitiUpcomingRun);
    }

    @Bean
    public TaskSubmitOperator taskSubmitOperator(APITaskConverter apiTaskConverter, TaskService taskService, RepositoryService repositoryService,
                                                 ActivitiUpcomingRun activitiUpcomingRun) {
        return new TaskSubmitOperatorImpl(apiTaskConverter, taskService, repositoryService, activitiUpcomingRun);
    }

    @Bean
    public TaskReceiveOperator taskReceiveOperator(APITaskConverter apiTaskConverter, TaskService taskService, ActivitiUpcomingRun activitiUpcomingRun) {
        return new TaskReceiveOperatorImpl(apiTaskConverter, taskService, activitiUpcomingRun);
    }

    @Bean
    public TaskTransferOperator taskTransferOperator(APITaskConverter apiTaskConverter, TaskService taskService, ActivitiUpcomingRun activitiUpcomingRun, RepositoryService repositoryService,ProcessEngineConfigurationImpl processEngineConfiguration) {
        return new TaskTransferOperatorImpl(apiTaskConverter, taskService, activitiUpcomingRun,repositoryService, processEngineConfiguration);
    }

    @Bean
    public TaskUrgeOperator taskUrgeOperator(APITaskConverter apiTaskConverter, TaskService taskService) {
        return new TaskUrgeOperatorImpl(apiTaskConverter, taskService);
    }

    @Bean
    public APITaskConverter apiTaskConverter(TaskService taskService) {
        return new APITaskConverter(taskService);
    }

    @Bean
    public TaskRuntimeConfiguration taskRuntimeConfiguration(@Autowired(required = false) List<TaskRuntimeEventListener<?>> taskRuntimeEventListeners,
                                                             @Autowired(required = false) List<VariableEventListener<?>> variableEventListeners) {
        return new TaskRuntimeConfigurationImpl(getInitializedTaskRuntimeEventListeners(taskRuntimeEventListeners),
                getInitializedTaskRuntimeEventListeners(variableEventListeners));
    }

    @Bean
    public InitializingBean registerTaskCreatedEventListener(RuntimeService runtimeService,
                                                             @Autowired(required = false) List<TaskRuntimeEventListener<TaskCreatedEvent>> listeners,
                                                             ToAPITaskCreatedEventConverter taskCreatedEventConverter) {
        return () -> runtimeService.addEventListener(new TaskCreatedListenerDelegate(getInitializedTaskRuntimeEventListeners(listeners),
                        taskCreatedEventConverter),
                ActivitiEventType.TASK_CREATED);
    }

    @Bean
    public InitializingBean registerTaskUpdatedEventListener(RuntimeService runtimeService,
                                                             @Autowired(required = false) List<TaskRuntimeEventListener<TaskUpdatedEvent>> listeners,
                                                             ToAPITaskUpdatedEventConverter taskCreatedEventConverter) {
        return () -> runtimeService.addEventListener(new TaskUpdatedListenerDelegate(getInitializedTaskRuntimeEventListeners(listeners),
                        taskCreatedEventConverter),
                ActivitiEventType.ENTITY_UPDATED);
    }

    private <T> List<T> getInitializedTaskRuntimeEventListeners(List<T> taskRuntimeEventListeners) {
        return taskRuntimeEventListeners != null ? taskRuntimeEventListeners : emptyList();
    }

    @Bean
    public InitializingBean registerTaskAssignedEventListener(RuntimeService runtimeService,
                                                              @Autowired(required = false) List<TaskRuntimeEventListener<TaskAssignedEvent>> listeners,
                                                              ToAPITaskAssignedEventConverter taskAssignedEventConverter) {
        return () -> runtimeService.addEventListener(new TaskAssignedListenerDelegate(getInitializedTaskRuntimeEventListeners(listeners),
                        taskAssignedEventConverter),
                ActivitiEventType.TASK_ASSIGNED);
    }

    @Bean
    public InitializingBean registerTaskCompletedEventListener(RuntimeService runtimeService,
                                                               @Autowired(required = false) List<TaskRuntimeEventListener<TaskCompletedEvent>> listeners,
                                                               APITaskConverter taskConverter) {
        return () -> runtimeService.addEventListener(new TaskCompletedListenerDelegate(getInitializedTaskRuntimeEventListeners(listeners),
                        new ToTaskCompletedConverter(taskConverter)),
                ActivitiEventType.TASK_COMPLETED);
    }

    @Bean
    public InitializingBean registerTaskCancelledEventListener(RuntimeService runtimeService,
                                                               @Autowired(required = false) List<TaskRuntimeEventListener<TaskCancelledEvent>> taskRuntimeEventListeners,
                                                               APITaskConverter taskConverter) {
        return () -> runtimeService.addEventListener(new TaskCancelledListenerDelegate(getInitializedTaskRuntimeEventListeners(taskRuntimeEventListeners),
                        new ToTaskCancelledConverter(taskConverter
                        )),
                ActivitiEventType.ENTITY_DELETED);
    }

    @Bean
    public InitializingBean registerTaskSuspendedListener(RuntimeService runtimeService,
                                                          @Autowired(required = false) List<TaskRuntimeEventListener<TaskSuspendedEvent>> listeners,
                                                          APITaskConverter taskConverter) {
        return () -> runtimeService.addEventListener(new TaskSuspendedListenerDelegate(getInitializedTaskRuntimeEventListeners(listeners),
                        new ToTaskSuspendedConverter(taskConverter)),
                ActivitiEventType.ENTITY_SUSPENDED);
    }

    @Bean
    public InitializingBean registerTaskActivatedListener(RuntimeService runtimeService,
                                                          @Autowired(required = false) List<TaskRuntimeEventListener<TaskActivatedEvent>> listeners,
                                                          APITaskConverter taskConverter) {
        return () -> runtimeService.addEventListener(new TaskActivatedListenerDelegate(getInitializedTaskRuntimeEventListeners(listeners),
                        new ToTaskActivatedConverter(taskConverter)),
                ActivitiEventType.ENTITY_ACTIVATED);
    }

    @Bean
    public ToAPITaskCreatedEventConverter apiTaskCreatedEventConverter(APITaskConverter taskConverter) {
        return new ToAPITaskCreatedEventConverter(taskConverter);
    }

    @Bean
    public ToAPITaskUpdatedEventConverter apiTaskUpdatedEventConverter(APITaskConverter taskConverter) {
        return new ToAPITaskUpdatedEventConverter(taskConverter);
    }

    @Bean
    public ToAPITaskAssignedEventConverter apiTaskAssignedEventConverter(APITaskConverter taskConverter) {
        return new ToAPITaskAssignedEventConverter(taskConverter);
    }

    @Bean
    public APITaskCandidateUserConverter apiTaskCandidateUserConverter() {
        return new APITaskCandidateUserConverter();
    }

    @Bean
    public ToAPITaskCandidateUserAddedEventConverter toAPITaskCandidateUserAddedEventConverter(APITaskCandidateUserConverter taskCandidateUserConverter) {
        return new ToAPITaskCandidateUserAddedEventConverter(taskCandidateUserConverter);
    }

    @Bean
    public InitializingBean registerTaskCandidateUserAddedEventListener(RuntimeService runtimeService,
                                                                        @Autowired(required = false) List<TaskRuntimeEventListener<TaskCandidateUserAddedEvent>> listeners,
                                                                        ToAPITaskCandidateUserAddedEventConverter taskCandidateUserAddedEventConverter) {
        return () -> runtimeService.addEventListener(new TaskCandidateUserAddedListenerDelegate(getInitializedTaskRuntimeEventListeners(listeners),
                        taskCandidateUserAddedEventConverter),
                ActivitiEventType.ENTITY_CREATED);
    }

    @Bean
    public InitializingBean registerTaskCandidateUserRemovedEventListener(RuntimeService runtimeService,
                                                                          @Autowired(required = false) List<TaskRuntimeEventListener<TaskCandidateUserRemovedEvent>> listeners,
                                                                          APITaskCandidateUserConverter taskCandidateUserConverter) {
        return () -> runtimeService.addEventListener(new TaskCandidateUserRemovedListenerDelegate(getInitializedTaskRuntimeEventListeners(listeners),
                        new ToTaskCandidateUserRemovedConverter(taskCandidateUserConverter)),
                ActivitiEventType.ENTITY_DELETED);
    }

    @Bean
    public APITaskCandidateGroupConverter apiTaskCandidateGroupConverter() {
        return new APITaskCandidateGroupConverter();
    }

    @Bean
    public ToAPITaskCandidateGroupAddedEventConverter toAPITaskCandidateGroupAddedEventConverter(APITaskCandidateGroupConverter taskCandidateGroupConverter) {
        return new ToAPITaskCandidateGroupAddedEventConverter(taskCandidateGroupConverter);
    }

    @Bean
    public InitializingBean registerTaskCandidateGroupAddedEventListener(RuntimeService runtimeService,
                                                                         @Autowired(required = false) List<TaskRuntimeEventListener<TaskCandidateGroupAddedEvent>> listeners,
                                                                         ToAPITaskCandidateGroupAddedEventConverter taskCandidateGroupAddedEventConverter) {
        return () -> runtimeService.addEventListener(new TaskCandidateGroupAddedListenerDelegate(getInitializedTaskRuntimeEventListeners(listeners),
                        taskCandidateGroupAddedEventConverter),
                ActivitiEventType.ENTITY_CREATED);
    }

    @Bean
    public InitializingBean registerTaskCandidateGroupRemovedEventListener(RuntimeService runtimeService,
                                                                           @Autowired(required = false) List<TaskRuntimeEventListener<TaskCandidateGroupRemovedEvent>> listeners,
                                                                           APITaskCandidateGroupConverter taskCandidateGroupConverter) {
        return () -> runtimeService.addEventListener(new TaskCandidateGroupRemovedListenerDelegate(getInitializedTaskRuntimeEventListeners(listeners),
                        new ToTaskCandidateGroupRemovedConverter(taskCandidateGroupConverter)),
                ActivitiEventType.ENTITY_DELETED);
    }

}
